#include "WeatherSystem.h"

WeatherSystem::WeatherSystem(SceneManager *mSceneMgr, Map *mMap)
{
	this->mSceneMgr = mSceneMgr;
	this->mWorldPoz = mMap->getWorldPoz();
	this->mMap = mMap;

	psRain = 0;
	psSnow = 0;
	nSnowLevel = 0;

	mParticleSystemNode = 0;

	mSun = mSceneMgr->createLight("sunLight");
	mSun->setType(Ogre::Light::LT_DIRECTIONAL);

	mSunNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("SunNode");
	mSunNode->setScale(0.01, 0.01, 0.01);
	mSunNode->setPosition(mSun->getPosition());

	bbs = mSceneMgr->createBillboardSet(1);
	bbs->setMaterialName("Examples/Flare");
	bb = bbs->createBillboard(0, 0, 0, Ogre::ColourValue::White);
	bb->setDimensions(10000,10000);
	mSunNode->attachObject(bbs);

	setDayTime(DayTime_Noon);
}

//--------------------------------------------------------------------------------------------------

WeatherSystem::~WeatherSystem(void)
{
	mSceneMgr->destroyLight("sunLight");
	mSceneMgr->destroySceneNode("SunNode");
	mSceneMgr->destroyBillboardSet(bbs);
	if(psRain!=0)
	{
		mSceneMgr->destroyParticleSystem(psRain);
	}
	if(psSnow!=0)
	{
		mSceneMgr->destroyParticleSystem(psSnow);
	}
}

//---------------------------------------------------------------------------------------------------

Light* WeatherSystem::getSunLight(void)
{
	return mSun;
}

//---------------------------------------------------------------------------------------------------

SceneNode* WeatherSystem::getSunObject(void)
{
	return mSunNode;
}

//---------------------------------------------------------------------------------------------------

WeatherSystem::eDayTime WeatherSystem::getDayTime(void)
{
	return mDayTime;
}

//---------------------------------------------------------------------------------------------------

void WeatherSystem::setDayTime(eDayTime dayTime)
{
	mDayTime = dayTime;

	mSceneMgr->setSkyDome(false,"");
	mSceneMgr->setSkyBox(false,"");

	switch(mDayTime)
	{
		case DayTime_Dawn:

				mSunNode->setPosition(Vector3(mWorldPoz.x + 0, mWorldPoz.y + 30, mWorldPoz.z - 256));
			    mSun->setDirection(Vector3(mWorldPoz.x + 0, mWorldPoz.y -30, mWorldPoz.z + 256));
				mSun->setDiffuseColour(Ogre::ColourValue::White);
				mSun->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
				bb->setColour(Ogre::ColourValue::White);
				mSceneMgr->setAmbientLight(Ogre::ColourValue(0.2, 0.2, 0.2));

				mSceneMgr->setSkyBox(true, "SkyBox/MorningSkyBox", 5, 8);
				mMap->getTerrainGlobalOptions()->setLightMapDirection(Ogre::Vector3(mWorldPoz.x + 0, mWorldPoz.y - 30, mWorldPoz.z + 256));
				mMap->getTerrainGlobalOptions()->setCompositeMapDiffuse(mSun->getDiffuseColour());

			break;
		case DayTime_Noon:
			
				mSunNode->setPosition(Vector3(mWorldPoz.x + 0, mWorldPoz.y + 256, mWorldPoz.z + 0));
			    mSun->setDirection(Vector3(mWorldPoz.x + 0, mWorldPoz.y - 256, mWorldPoz.z + 0));
				mSun->setDiffuseColour(Ogre::ColourValue::White);
				mSun->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
				bb->setColour(Ogre::ColourValue::White);
				mSceneMgr->setAmbientLight(Ogre::ColourValue(0.2, 0.2, 0.2));

				mSceneMgr->setSkyDome(true, "SkyBox/CloudySkyBox", 5, 8);
				mMap->getTerrainGlobalOptions()->setLightMapDirection(Ogre::Vector3(mWorldPoz.x + 0, mWorldPoz.y - 256, mWorldPoz.z + 0));
				mMap->getTerrainGlobalOptions()->setCompositeMapDiffuse(mSun->getDiffuseColour());

			break;
		case DayTime_AfterNoon:

				mSunNode->setPosition(Vector3(mWorldPoz.x + 0, mWorldPoz.y + 80, mWorldPoz.z + 125));
			    mSun->setDirection(Vector3(mWorldPoz.x + 0, mWorldPoz.y - 80, mWorldPoz.z -60));
				mSun->setDiffuseColour(Ogre::ColourValue::White);
				mSun->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
				bb->setColour(Ogre::ColourValue::White);
				mSceneMgr->setAmbientLight(Ogre::ColourValue(0.2, 0.2, 0.2));

				mSceneMgr->setSkyDome(true, "SkyBox/CloudySkyBox", 5, 8);
				mMap->getTerrainGlobalOptions()->setLightMapDirection(Ogre::Vector3(mWorldPoz.x + 0, mWorldPoz.y - 80, mWorldPoz.z -60));
				mMap->getTerrainGlobalOptions()->setCompositeMapDiffuse(mSun->getDiffuseColour());

			break;
		case DayTime_SunSet:

				mSunNode->setPosition(Vector3(mWorldPoz.x + 0, mWorldPoz.y + 30, mWorldPoz.z + 256));
			    mSun->setDirection(Vector3(mWorldPoz.x + 0, mWorldPoz.y - 30, mWorldPoz.z -256));
				mSun->setDiffuseColour(Ogre::ColourValue::White);
				mSun->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
				bb->setColour(Ogre::ColourValue::White);
				mSceneMgr->setAmbientLight(Ogre::ColourValue(0.2, 0.2, 0.2));

				mSceneMgr->setSkyBox(true, "SkyBox/MorningSkyBox", 5, 8);
				mMap->getTerrainGlobalOptions()->setLightMapDirection(Ogre::Vector3(mWorldPoz.x + 0, mWorldPoz.y - 30, mWorldPoz.z -256));
				mMap->getTerrainGlobalOptions()->setCompositeMapDiffuse(mSun->getDiffuseColour());


			break;
		case DayTime_Night:

				mSunNode->setPosition(Vector3(mWorldPoz.x + 0, mWorldPoz.y - 50, mWorldPoz.z + 0));
			    mSun->setDirection(Vector3(mWorldPoz.x + 0, mWorldPoz.y + 50, mWorldPoz.z + 0));
				mSun->setDiffuseColour(Ogre::ColourValue(0.1, 0.1, 0.1));
				mSun->setSpecularColour(Ogre::ColourValue(0.4, 0.4, 0.4));
				bb->setColour(Ogre::ColourValue::White);
				mSceneMgr->setAmbientLight(Ogre::ColourValue(0.1, 0.1, 0.1));

				mSceneMgr->setSkyBox(true, "SkyBox/SunsetSkyBox", 5, 8);
				mMap->getTerrainGlobalOptions()->setLightMapDirection(Ogre::Vector3(mWorldPoz.x + 0, mWorldPoz.y - 50, mWorldPoz.z + 0));
				mMap->getTerrainGlobalOptions()->setCompositeMapDiffuse(mSun->getDiffuseColour());

			break;

	}

	
	mMap->getTerrain()->dirtyLightmap();
	mMap->getTerrain()->updateDerivedData();
}

//---------------------------------------------------------------------------------------------------

void WeatherSystem::advanceDayTime(void)
{
	switch(mDayTime)
	{
		case DayTime_Dawn:

			setDayTime(DayTime_Noon);

			break;
		case DayTime_Noon:
			
			setDayTime(DayTime_AfterNoon);

			break;
		case DayTime_AfterNoon:

			setDayTime(DayTime_SunSet);

			break;
		case DayTime_SunSet:

			setDayTime(DayTime_Night);

			break;
		case DayTime_Night:

			setDayTime(DayTime_Dawn);

			break;

	}
}

//---------------------------------------------------------------------------------------------------

void WeatherSystem::createRain(void)
{
	if(psRain==0)
	{
		std::cout << "\nWeatherSystem: creating new rain...";
		ParticleSystem::setDefaultNonVisibleUpdateTimeout(5);
		std::cout << "\nWeatherSystem: creating particle system scene node...";
		if(mParticleSystemNode == 0)
		{
			mParticleSystemNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("ParticleSystemNode");
		}
		psRain = mSceneMgr->createParticleSystem("Rain", "Weather/Rain");
		std::cout << "\nWeatherSystem: number of rain emitters: " << psRain->getNumEmitters();
		std::cout << "\nWeatherSystem: setting rain position to:" << mWorldPoz.x << ":" <<  mWorldPoz.y+30 << ":" << mWorldPoz.z;
		mParticleSystemNode->setPosition(Ogre::Vector3(mWorldPoz.x,mWorldPoz.y+30,mWorldPoz.z));
		mParticleSystemNode->setScale(0.5,0.5,0.5);
		std::cout << "\nWeatherSystem: setting rain speed to 5";
		psRain->fastForward(5); 
		psRain->setVisible(true);
		mParticleSystemNode->attachObject(psRain);
		mSceneMgr->setSkyDome(false,"");
	    mSceneMgr->setSkyBox(false,"");
		mSceneMgr->setSkyDome(true, "SkyBox/StormySkyBox", 5, 8);
	}
	else
	{
		std::cout << "\nWeatherSystem: setting rain visible...";
		psRain->setVisible(true);
		mSceneMgr->setSkyDome(false,"");
	    mSceneMgr->setSkyBox(false,"");
		mSceneMgr->setSkyDome(true, "SkyBox/StormySkyBox", 5, 8);
	}
}

//---------------------------------------------------------------------------------------------------

void WeatherSystem::stopRain(void)
{
	if(psRain!=0)
	{
		std::cout << "\nWeatherSystem: stopping rain...";
		psRain->setVisible(false);

	//restore skybox
	mSceneMgr->setSkyDome(false,"");
	mSceneMgr->setSkyBox(false,"");
	switch(mDayTime)
	{
		case DayTime_Dawn:
			mSceneMgr->setSkyBox(true, "SkyBox/MorningSkyBox", 5, 8);
			break;
		case DayTime_Noon:
			mSceneMgr->setSkyDome(true, "SkyBox/CloudySkyBox", 5, 8);
			break;
		case DayTime_AfterNoon:
			mSceneMgr->setSkyDome(true, "SkyBox/CloudySkyBox", 5, 8);
			break;
		case DayTime_SunSet:
			mSceneMgr->setSkyBox(true, "SkyBox/MorningSkyBox", 5, 8);
			break;
		case DayTime_Night:
			mSceneMgr->setSkyBox(true, "SkyBox/SunsetSkyBox", 5, 8);
			break;

	}
	}
}

//----------------------------------------------------------------------------------------------------

void WeatherSystem::toggleRain(void)
{
	if(psRain==0)
	{
		createRain();
	}
	else
	{
		if(psRain->isVisible())
		{
			psRain->setVisible(false);
		}
		else
		{
			psRain->setVisible(true);
		}
	}
}

//----------------------------------------------------------------------------------------------------

bool WeatherSystem::isRaining(void)
{
	if(psRain==0)
	{
		return false;
	}
	else
	{
		if(psRain->isVisible())
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}

//----------------------------------------------------------------------------------------------------


void WeatherSystem::createSnow(void)
{
	if(psSnow==0)
	{
		std::cout << "\nWeatherSystem: creating new Snow...";
		ParticleSystem::setDefaultNonVisibleUpdateTimeout(5);
		std::cout << "\nWeatherSystem: creating particle system scene node...";
		if(mParticleSystemNode == 0)
		{
			mParticleSystemNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("ParticleSystemNode");
		}
		psSnow = mSceneMgr->createParticleSystem("Snow", "Weather/Snow");
		std::cout << "\nWeatherSystem: number of Snow emitters: " << psSnow->getNumEmitters();
		std::cout << "\nWeatherSystem: setting Snow position to:" << mWorldPoz.x << ":" <<  mWorldPoz.y+30 << ":" << mWorldPoz.z;
		mParticleSystemNode->setPosition(Ogre::Vector3(mWorldPoz.x,mWorldPoz.y+30,mWorldPoz.z));
		mParticleSystemNode->setScale(0.5,0.5,0.5);
		psSnow->setVisible(true);
		mParticleSystemNode->attachObject(psSnow);
		mSceneMgr->setSkyDome(false,"");
	    mSceneMgr->setSkyBox(false,"");
		mSceneMgr->setSkyDome(true, "SkyBox/SnowySkyBox", 5, 8);
	}
	else
	{
		std::cout << "\nWeatherSystem: setting Snow visible...";
		psSnow->setVisible(true);
		mSceneMgr->setSkyDome(false,"");
	    mSceneMgr->setSkyBox(false,"");
		mSceneMgr->setSkyDome(true, "SkyBox/SnowySkyBox", 5, 8);
	}
}

//---------------------------------------------------------------------------------------------------

void WeatherSystem::stopSnow(void)
{
	if(psSnow!=0)
	{
		std::cout << "\nWeatherSystem: stopping Snow...";
		psSnow->setVisible(false);

	//restore skybox
	mSceneMgr->setSkyDome(false,"");
	mSceneMgr->setSkyBox(false,"");
	switch(mDayTime)
	{
		case DayTime_Dawn:
			mSceneMgr->setSkyBox(true, "SkyBox/MorningSkyBox", 5, 8);
			break;
		case DayTime_Noon:
			mSceneMgr->setSkyDome(true, "SkyBox/CloudySkyBox", 5, 8);
			break;
		case DayTime_AfterNoon:
			mSceneMgr->setSkyDome(true, "SkyBox/CloudySkyBox", 5, 8);
			break;
		case DayTime_SunSet:
			mSceneMgr->setSkyBox(true, "SkyBox/MorningSkyBox", 5, 8);
			break;
		case DayTime_Night:
			mSceneMgr->setSkyBox(true, "SkyBox/SunsetSkyBox", 5, 8);
			break;

	}
	}
}

//----------------------------------------------------------------------------------------------------

void WeatherSystem::toggleSnow(void)
{
	if(psSnow==0)
	{
		createSnow();
	}
	else
	{
		if(psSnow->isVisible())
		{
			psSnow->setVisible(false);
		}
		else
		{
			psSnow->setVisible(true);
		}
	}
}

//----------------------------------------------------------------------------------------------------

bool WeatherSystem::isSnowing(void)
{
	if(psSnow==0)
	{
		return false;
	}
	else
	{
		if(psSnow->isVisible())
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}


//----------------------------------------------------------------------------------------------------

void WeatherSystem::setSnowLevel(int snowLevel)
{
	if(snowLevel == 0)
	{
			
				Ogre::StringVector *vec = new Ogre::StringVector();
				vec->push_back("realgrass_diffusespecular.dds");
				vec->push_back("realgrass_normalheight.dds");

				mMap->changeTexture(0,1,vec);
				mMap->initBlendMaps();	
			
				nSnowLevel = 0;
	}
	else if(snowLevel == 1)
	{
				Ogre::StringVector *vec = new Ogre::StringVector();
				vec->push_back("realgrass_snow_1_diffusespecular.dds");
				vec->push_back("realgrass_snow_1_normalheight.dds");

				mMap->changeTexture(0,1,vec);
				mMap->initBlendMaps();

				nSnowLevel = 1;
	}
    else if(snowLevel == 2)
	{
				Ogre::StringVector *vec = new Ogre::StringVector();
				vec->push_back("realgrass_snow_2_diffusespecular.dds");
				vec->push_back("realgrass_snow_2_normalheight.dds");

				mMap->changeTexture(0,1,vec);
				mMap->initBlendMaps();

				nSnowLevel = 2;
	}
	else if(snowLevel == 3)
	{
				Ogre::StringVector *vec = new Ogre::StringVector();
				vec->push_back("realgrass_snow_3_diffusespecular.dds");
				vec->push_back("realgrass_snow_3_normalheight.dds");

				mMap->changeTexture(0,1,vec);
				mMap->initBlendMaps();

				nSnowLevel =3;
	}
	else if(snowLevel == 4)
	{
				Ogre::StringVector *vec = new Ogre::StringVector();
				vec->push_back("realgrass_snow_4_diffusespecular.dds");
				vec->push_back("realgrass_snow_4_normalheight.dds");

				mMap->changeTexture(0,1,vec);
				mMap->initBlendMaps();

				nSnowLevel = 4;
	}
}

//----------------------------------------------------------------------------------------------------

void WeatherSystem::advanceSnowLevel(void)
{
	nSnowLevel++;
	if(nSnowLevel>4) nSnowLevel = 0;
	setSnowLevel(nSnowLevel);
}

//----------------------------------------------------------------------------------------------------

int WeatherSystem::getSnowLevel(void)
{
	return nSnowLevel;
}

//----------------------------------------------------------------------------------------------------